using System;
using System.Text;
using System.Security.Cryptography;
using System.Globalization;
using System.Web;

namespace Antix.Security
{
    /// <summary>
    /// Simple Encryption rountines.
    /// 
    /// Declared statically so that they can be called without instanciating the class.
    /// 
    /// Version 1.0 
    /// 2005-10-06
    /// </summary>
    public sealed class CryptoSimple
    {
        /// <summary>
        /// The key is stored in the encryption at this position
        /// </summary>
        public const int KEYPOSITION = 13;
        /// <summary>
        /// The key is stored in the encryption at this position is the encrypted string is smaller than KEYPOSITION
        /// </summary>
        public const int KEYPOSITIONSMALL = 3;

        #region Encrypt

        /// <summary>
        /// Encrypts a string
        /// 
        /// By shifting the byte values of a string chars by a random 
        /// number. This number is inserted into the result at KEYPOSITION.
        /// 
        /// This is not a very secure method of encryption and should
        /// not be used for data such as credit card numbers etc.
        /// </summary>
        /// <example>
        ///		
        /// </example>
        /// <param name="value">String to encrypt</param>
        /// <returns>Encrypted string</returns>
        public static string Encrypt(string value)
        {
            string encrypted = "";

            if (value != null)
            {
                int valueLength = value.Length;
                if (valueLength > 0)
                {
                    // get a random key
                    int key = new Random().Next(65, 96);
                    int position = 0;

                    // get the bytes for the string
                    byte[] bytes = Encoding.UTF8.GetBytes(value);

                    // shift by the key
                    for (position = 0; position < bytes.Length; position++)
                    {
                        int newValue = bytes[position] + key;
                        if (newValue > byte.MaxValue) { newValue -= byte.MaxValue; }

                        bytes[position] = (byte)newValue;
                    }

                    // insert the key
                    encrypted = Convert.ToBase64String(bytes);
                    if (encrypted.Length <= KEYPOSITION)
                    {
                        // string not big enough place key at KEYPOSITION
                        encrypted = encrypted.Insert(KEYPOSITIONSMALL, Convert.ToChar(key).ToString());
                    }
                    else
                    {
                        encrypted = encrypted.Insert(KEYPOSITION, Convert.ToChar(key).ToString());
                    }
                }
            }

            return encrypted;
        }

        #endregion

        #region Decrypt

        /// <summary>
        /// Decrypt an encrypted string
        /// </summary>
        /// <param name="value">Encrypted string</param>
        /// <returns>Decrypted string</returns>
        public static string Decrypt(string value)
        {
            string decrypted = "";

            if (value != null && value.Length > 1)
            {
                int keyPosition;

                // if the string is smaller than the KEYPOSITION use KEYPOSITIONSMALL
                if (value.Length <= KEYPOSITION) { keyPosition = KEYPOSITIONSMALL; }
                else { keyPosition = KEYPOSITION; }

                // retrieve the key
                int key = Encoding.UTF8.GetBytes(value.Substring(keyPosition, 1))[0];

                // get shifted bytes
                byte[] bytes = Convert.FromBase64String(value.Remove(keyPosition, 1));

                // shift back by the key
                for (int position = 0; position < bytes.Length; position++)
                {
                    int newValue = bytes[position] - key;
                    if (newValue < byte.MinValue) { newValue += byte.MaxValue; }

                    bytes[position] = (byte)newValue;
                }

                decrypted = Encoding.UTF8.GetString(bytes);
            }

            return decrypted;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Private constructor 
        /// 
        /// Prevents class being instanciated
        /// </summary>
        private CryptoSimple() { }

        #endregion
    }
}